package lexer;

import java.util.Scanner;

/**
 * 词法分析器
 * Created by weijianyu on 2017/1/11.
 */
public class Lexer {
    // 定义标签
    public static final int EOI = 0;    // 结束
    public static final int SEMI = 1;   // ;
    public static final int PLUS = 2;   // +
    public static final int TIMES = 3;  // *
    public static final int LP = 4;     // (
    public static final int RP = 5;     // )
    public static final int NUM_OR_ID = 6;  // 数字
    public static final int UNKNOWN_SYMBOL = 7; // 未定义符号

    private int lookAhead = -1;     //当前分割字符串指向的标签

    public String yytext = "";  //当前分析字符
    public int yylength = 0;    //当前分析字符长度
    public int yylineno = 0;    //当前分析字符串行号

    private String input_buffer = "";   //缓冲区
    private String current = "";

    private boolean isAlnum(char c) {
        if (Character.isLetterOrDigit(c)) {
            return true;
        }
        return false;
    }

    private int lex() {
        while (true) {
            while (current == "") {
                Scanner scanner = new Scanner(System.in);
                while (true) {
                    String line = scanner.nextLine();
                    if (line.equals("end")) {
                        break;
                    }
                    input_buffer += line;
                }
                scanner.close();

                if (input_buffer.length() == 0) {
                    current = "";
                    return EOI;
                }

                current = input_buffer;
                ++yylineno;
                current = current.trim();
            }

            if (0 == current.length()) {
                return EOI;
            }

            for (int i = 0; i < current.length(); i++) {
                yylength = 0;
                yytext = current.substring(0, 1);
                switch (current.charAt(i)) {
                    case ';':
                        current = current.substring(1);
                        return SEMI;
                    case '+':
                        current = current.substring(1);
                        return PLUS;
                    case '*':
                        current = current.substring(1);
                        return TIMES;
                    case '(':
                        current = current.substring(1);
                        return LP;
                    case ')':
                        current = current.substring(1);
                        return RP;
                    case '\n':
                    case '\t':
                    case ' ':
                        current = current.substring(1);
                        break;
                    default:
                        if (isAlnum(current.charAt(i))) {
                            while (isAlnum(current.charAt(i))) {
                                i++;
                                yylength++;
                            }
                            yytext = current.substring(0, yylength);
                            current = current.substring(yylength);
                            return NUM_OR_ID;
                        } else {
                            System.out.println("Ignoring illegal input: " + current.charAt(i));
                        }
                        break;
                }
            }
        }
    }

    public boolean match(int token) {
        if (lookAhead == -1) {
            lookAhead = lex();
        }
        return token == lookAhead;
    }

    public void advance() {
        lookAhead = lex();
    }

    private String token() {
        String token = "";
        switch (lookAhead) {
            case EOI:
                token = "EOI";
                break;
            case PLUS:
                token = "PLUS";
                break;
            case TIMES:
                token = "TIMES";
                break;
            case NUM_OR_ID:
                token = "NUM_OR_ID";
                break;
            case SEMI:
                token = "SEMI";
                break;
            case LP:
                token = "LP";
                break;
            case RP:
                token = "RP";
                break;
        }
        return token;
    }

    public void runLexer() {
        while (!match(EOI)) {
            System.out.println("Token: " + token() + ", Symbol: " + yytext);
            advance();
        }
    }

    public static void main(String[] args) {
        new Lexer().runLexer();
    }
}
